<template>
  <div class="linked-list-container">
    <div class="controls">
      <input v-model.number="newItem" placeholder="输入新元素" type="number">
      <button @click="addHead">添加到头部</button>
      <button @click="addTail">添加到尾部</button>
      <button @click="removeHead">移除头部</button>
      <button @click="removeTail">移除尾部</button>
      <button @click="searchItem">搜索元素</button>
      <button @click="runTests">运行测试</button>
    </div>
    <div id="graph"></div>
    <div v-if="testResults" class="test-results">
      <h3>测试结果:</h3>
      <ul>
        <li v-for="(result, index) in testResults" :key="index">
          测试 {{ index + 1 }}: {{ result ? '✅ 通过' : '❌ 失败' }}
        </li>
      </ul>
    </div>
  </div>
</template>

<script>
import * as d3 from 'd3';

export default {
  name: 'LinkedList',
  data() {
    return {
      list: [],
      newItem: '',
      graph: null,
      simulation: null,
      testResults: null,
      nodeId: 0
    };
  },
  mounted() {
    this.initGraph();
  },
  methods: {
    initGraph() {
      const width = 800;
      const height = 400;

      this.graph = d3.select('#graph')
        .append('svg')
        .attr('width', width)
        .attr('height', height);

      this.simulation = d3.forceSimulation()
        .force('link', d3.forceLink().id(d => d.id).distance(100))
        .force('charge', d3.forceManyBody().strength(-100))
        .force('center', d3.forceCenter(width / 2, height / 2))
        .force('collide', d3.forceCollide().radius(30));
    },
    addHead() {
      if (this.newItem === '') return;
      const newNode = { 
        id: ++this.nodeId,
        value: Number(this.newItem),
        x: 400,
        y: 200
      };
      this.list.unshift(newNode);
      this.updateGraph();
      this.newItem = '';
    },
    addTail() {
      if (this.newItem === '') return;
      const newNode = {
        id: ++this.nodeId,
        value: Number(this.newItem),
        x: 400,
        y: 200
      };
      this.list.push(newNode);
      this.updateGraph();
      this.newItem = '';
    },
    removeHead() {
      if (this.list.length > 0) {
        this.list.shift();
        this.updateGraph();
      }
    },
    removeTail() {
      if (this.list.length > 0) {
        this.list.pop();
        this.updateGraph();
      }
    },
    searchItem() {
      const value = Number(this.newItem);
      const index = this.list.findIndex(node => node.value === value);
      if (index !== -1) {
        alert(`元素 ${value} 位于位置 ${index}`);
      } else {
        alert('元素未找到');
      }
    },
    updateGraph() {
      // 更新节点
      const nodes = this.graph.selectAll('.node')
        .data(this.list, d => d.id)
        .join(
          enter => {
            const g = enter.append('g')
              .attr('class', 'node')
              .attr('transform', d => `translate(${d.x},${d.y})`);
            
            g.append('circle')
              .attr('r', 20)
              .attr('fill', '#4CAF50');
            
            g.append('text')
              .attr('text-anchor', 'middle')
              .attr('dy', '.3em')
              .attr('fill', 'white')
              .text(d => d.value);
            
            return g;
          },
          update => update,
          exit => exit.remove()
        );

      // 更新连线
      const links = this.list.slice(0, -1).map((node, index) => ({
        source: node.id,
        target: this.list[index + 1].id
      }));

      const linksG = this.graph.selectAll('.link')
        .data(links, d => `${d.source}-${d.target}`)
        .join(
          enter => enter.append('line')
            .attr('class', 'link')
            .attr('stroke', '#666')
            .attr('stroke-width', 2),
          update => update,
          exit => exit.remove()
        );

      // 更新力学模拟
      this.simulation.nodes(this.list);
      this.simulation.force('link').links(links);
      this.simulation.alpha(1).restart();

      // 更新位置
      this.simulation.on('tick', () => {
        nodes.attr('transform', d => `translate(${d.x},${d.y})`);
        linksG
          .attr('x1', d => d.source.x)
          .attr('y1', d => d.source.y)
          .attr('x2', d => d.target.x)
          .attr('y2', d => d.target.y);
      });
    },
    runTests() {
      const originalList = [...this.list];
      this.list = [];
      this.testResults = [];
      
      try {
        // 测试1: 添加到头部
        this.newItem = '10';
        this.addHead();
        this.testResults.push(this.list[0]?.value === 10);

        // 测试2: 添加到尾部
        this.newItem = '20';
        this.addTail();
        this.testResults.push(this.list[1]?.value === 20);

        // 测试3: 移除头部
        this.removeHead();
        this.testResults.push(this.list.length === 1 && this.list[0]?.value === 20);

        // 测试4: 移除尾部
        this.removeTail();
        this.testResults.push(this.list.length === 0);

        // 测试5: 搜索元素
        this.list = [{id:1,value:5}, {id:2,value:10}, {id:3,value:15}];
        this.newItem = '10';
        this.searchItem(); // 应该弹出找到提示
        this.testResults.push(true); // 手动确认

      } finally {
        this.list = originalList;
        this.updateGraph();
      }
    }
  }
};
</script>

<style scoped>
.linked-list-container {
  margin: 20px;
  font-family: Arial, sans-serif;
}

.controls {
  margin-bottom: 20px;
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

input {
  padding: 8px;
  border: 1px solid #ccc;
  border-radius: 4px;
  width: 150px;
}

button {
  padding: 8px 16px;
  background-color: #4CAF50;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  transition: background-color 0.3s;
}

button:hover {
  background-color: #45a049;
}

#graph {
  margin-top: 20px;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.test-results {
  margin-top: 20px;
  padding: 15px;
  background-color: #f8f9fa;
  border-radius: 4px;
}

.test-results h3 {
  margin-top: 0;
  color: #333;
}

.test-results li {
  margin: 5px 0;
  padding: 5px;
  list-style-type: none;
  background-color: white;
  border-radius: 3px;
}
</style>